package cn.tedu._07springaop.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * Aspect注解:表示当前类是一个切面类
 * 可以定义切面方法,为目标方法进行功能增强
 */
@Aspect
@Component
public class LogAspect {
    /**
     * Before注解:前置通知,在目标方法执行之前执行;
     * value参数:切入点表达式,指定哪些方法需要被植入增强逻辑
     */
    @Before(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public void beforeMethod(JoinPoint joinPoint)  {
        /**
         * JoinPoint参数:连接点参数,表示当前正在执行的目标方法
         * 1.获取目标方法名称:从方法签名名获取方法名
         * 2.获取目标方法的参数
         */
        String name = joinPoint.getSignature().getName();//获取方法名称
        String args = Arrays.toString(joinPoint.getArgs());//获取参数列表

        System.out.println("[前置通知]:" + name + "方法开始,参数为:" + args);
    }

    /**
     * 2. 返回通知:目标方法成功结束后执行
     * returning参数:获取目标方法的返回值
     */
    @AfterReturning(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))", returning = "r")
    public void afterReturningMethod(JoinPoint joinPoint, Object r) {
        String name = joinPoint.getSignature().getName();

        System.out.println("[返回通知]:" + name + "方法结束,结果为:" + r);
    }

    /**
     * 3.后置通知:目标方法成功结束和异常结束都会执行,一般用于释放资源的操作;
     * <p>
     * 问题:
     */
    @After(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public void afterMethod(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        System.out.println("[后置通知]:" + name + "方法彻底结束");
    }

    /**
     * 异常通知
     */
    @AfterThrowing(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))", throwing = "ex")
    public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex) {
        String name = joinPoint.getSignature().getName();
        String message = ex.getMessage();
        System.out.println("[异常通知]:" + name + "方法异常:" + message);

        /**
         * 5.环绕通知:
         * 1.目标方法执行前和执行后都会执行
         * 2.目标方法抛出异常也会执行
         * 3.可以获取到目标方法的返回值
         * 4.可以获取到异常对象
         * 环绕==前置+返回+异常+后置
         *
         * ProceedingJoinPoint是JoinPoint连接点的一个子类,可以执行目标方法
         */
        }
    @Around(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public Object aroundMethod(ProceedingJoinPoint joinPoint){
        Object result = null;
        try {
            //前置通知
            System.out.println("111-前置通知");
            //执行目标方法
            result = joinPoint.proceed();
            //返回通知
            System.out.println("111-返回通知");
        }catch (Throwable e){
            System.out.println("111-异常通知");
            throw new RuntimeException(e);
        }finally {
            System.out.println("111-后置通知");
        }
        return result;
    }

}
